package gov.pbc.nn.core.bdf.authoritydelegation.service.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import com.bstek.bdf2.core.business.IDept;
import com.bstek.bdf2.core.business.IPosition;
import com.bstek.bdf2.core.model.DefaultPosition;
import com.bstek.bdf2.core.model.Group;
import com.bstek.bdf2.core.model.Role;
import com.bstek.bdf2.core.model.Url;
import com.bstek.bdf2.core.orm.ParseResult;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;
import com.bstek.dorado.data.provider.filter.SingleValueFilterCriterion;

import gov.pbc.nn.core.bdf.authoritydelegation.AuthoritydelegationHibernateDao;
import gov.pbc.nn.core.bdf.authoritydelegation.model.ResourceAllocation;
import gov.pbc.nn.core.bdf.authoritydelegation.service.IAuthoritydelegationService;
import gov.pbc.nn.core.bdf.service.DeptService.DefaultDeptRowMapper;
import gov.pbc.nn.core.bdf.service.UserService.DefaultUserRowMapper;
import gov.pbc.nn.core.dao.PbcnnCoreJdbcDao;
import gov.pbc.nn.core.utils.EntityRowMapperUtils;

@Service(IAuthoritydelegationService.BEAN_ID_)
public class AuthoritydelegationServiceImpl extends AuthoritydelegationHibernateDao
		implements IAuthoritydelegationService {

	@Resource(name=PbcnnCoreJdbcDao.BEAN_ID)
	private PbcnnCoreJdbcDao jdbcDao;
	
	public Collection<Url> findControllableUrls(String owner) {
		Page<Url> page = new Page<Url>(Integer.MAX_VALUE, 1);
		findControllableResources(ResourceAllocation.ResourceType.U, page, owner, null);
		return page.getEntities();
	}

	public Collection<Url> findControllableUrls(String parentId, String owner) {
		Collection<Url> urls = this.findControllableUrls(owner);
		if (StringUtils.isNotEmpty(parentId)) {
			Collection<Url> children = new ArrayList<Url>();
			for (Url url : urls) {
				if (parentId.equals(url.getParentId())) {
					children.add(url);
				}
			}
			return children;
		} else {
			Collection<Url> topUrl = new ArrayList<Url>();
			Set<String> set = new HashSet<String>();
			for (Url url : urls) {
				Url tu = this.getTopUrl(url, urls);
				if (!set.contains(tu.getId())) {
					set.add(tu.getId());
					topUrl.add(tu);
				}
			}
			return topUrl;
		}
	}

	private Url getTopUrl(Url url, Collection<Url> urls) {
		if (StringUtils.isEmpty(url.getParentId())) {
			return url;
		} else {
			for (Url u : urls) {
				if (url.getId().equals(u.getId()))
					continue;
				if (url.getParentId().equals(u.getId())) {
					return this.getTopUrl(u, urls);
				}
			}
		}
		return url;
	}

	public void findControllableUsers(Page<UserDetails> page, String owner, Criteria criteria) {
		findControllableResources(ResourceAllocation.ResourceType.E, page, owner, criteria);
	}

	public void findControllableDepts(Page<IDept> page, String owner, Criteria criteria) {
		findControllableResources(ResourceAllocation.ResourceType.D, page, owner, criteria);
	}

	public Collection<IDept> findControllableDepts(String owner,String parentId) {
		Page<IDept> page = new Page<IDept>(Integer.MAX_VALUE, 1);
		Criteria c = new Criteria();
		if(StringUtils.isNotBlank(parentId)){
			SingleValueFilterCriterion criterion = new SingleValueFilterCriterion();
			criterion.setProperty("parentId");
			criterion.setValue(parentId);
			criterion.setExpression("=");
			c.addCriterion(criterion);
		}
		findControllableResources(ResourceAllocation.ResourceType.D, page, owner, c);
		Collection<IDept> deptList = page.getEntities();
		return deptList;
	}

	public void findControllableGroups(Page<Group> page, String owner, Criteria criteria) {
		findControllableResources(ResourceAllocation.ResourceType.G, page, owner, criteria);
	}

	public void findControllablePositions(Page<IPosition> page, String owner, Criteria criteria) {
		findControllableResources(ResourceAllocation.ResourceType.P, page, owner, criteria);
	}

	public void findControllableRoles(Page<Role> page, String owner, Criteria criteria) {
		findControllableResources(ResourceAllocation.ResourceType.R, page, owner, criteria);
	}

	@SuppressWarnings("unchecked")
	private <T> void findControllableResources(ResourceAllocation.ResourceType resourceType, Page<T> page, String owner,
			Criteria criteria) {
//		StringBuffer queryString = new StringBuffer("select resourceId from " + ResourceAllocation.class.getName()
//				+ " where resourceOwner=:resourceOwner and resourceType=:resourceType");
//		StringBuffer countQueryString = new StringBuffer("select count(*) from " + ResourceAllocation.class.getName()
//				+ " where resourceOwner=:resourceOwner and resourceType=:resourceType");
		Map<String, Object> parametersMap = new HashMap<String, Object>();
//		Page<String> page1 = new Page<String>(page.getPageSize(), page.getPageNo());
		parametersMap.put("resourceOwner", owner);
		if (ResourceAllocation.ResourceType.E.equals(resourceType)) {
			// 用户
			String sql = "SELECT\n" +
					"	t.*\n" +
					"FROM\n" +
					"	(\n" +
					"		SELECT\n" +
					"			u.*, d.ID_ as DEPT_ID_,d.NAME_ AS DEPT_NAME_\n" +
					"		FROM\n" +
					"			bdf2_resource_allocation ra\n" +
					"		INNER JOIN bdf2_user_dept ud ON ra.RESOURCE_ID_ = ud.USERNAME_\n" +
					"		AND ra.RESOURCE_TYPE_ = 'E'\n" +
					"		INNER JOIN t_dept d ON d.ID_ = ud.DEPT_ID_\n" +
					"		INNER JOIN t_user u ON ud.USERNAME_ = u.USERNAME_\n" +
					"		AND u.USERNAME_ = ra.RESOURCE_ID_\n" +
					"		WHERE\n" +
					"			ra.RESOURCE_OWNER_ =:resourceOwner\n" +
					"	) t\n" +
					"WHERE\n" +
					"	1 = 1";
			//2017-12-05
			sql = "SELECT\n" +
					"	t.*\n" +
					"FROM\n" +
					"	(\n" +
					"		SELECT\n" +
					"			u.*, d.ID_ AS DEPT_ID_,\n" +
					"			d.NAME_ AS DEPT_NAME_\n" +
					"		FROM\n" +
					"			bdf2_resource_allocation ra\n" +
					"		INNER JOIN bdf2_dept d ON ra.RESOURCE_ID_ = d.ID_\n" +
					"		INNER JOIN bdf2_user_dept ud ON ud.DEPT_ID_ = d.ID_\n" +
					"		INNER JOIN bdf2_user u ON ud.USERNAME_ = u.USERNAME_\n" +
					"		WHERE\n" +
					"			ra.RESOURCE_TYPE_ = 'D'\n" +
					"		AND ra.RESOURCE_OWNER_ =:resourceOwner\n" +
					"	) t\n" +
					"WHERE\n" +
					"	1 = 1";
			
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "t");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new DefaultUserRowMapper(), parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.E.name());
//			try {
//				this.pagingQuery(page1, queryString.toString(), countQueryString.toString(), parametersMap);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			List<UserDetails> userList = new ArrayList<UserDetails>();
//			IUserService userService = ContextHolder.getBean(IUserService.BEAN_ID);
//			for (String user : page1.getEntities()) {
//				userList.add(userService.loadUserByUsername(user));
//			}
//			page.setEntities((Collection<T>) userList);
//			page.setEntityCount(page1.getEntityCount());
		} else if (ResourceAllocation.ResourceType.P.equals(resourceType)) {
			// 岗位
			String sql = "SELECT\n" +
					"	p.*\n" +
					"FROM\n" +
					"	bdf2_resource_allocation ra\n" +
					"INNER JOIN bdf2_position p ON p.ID_ = ra.RESOURCE_ID_\n" +
					"AND ra.RESOURCE_TYPE_ = 'P'\n" +
					"WHERE\n" +
					"	ra.RESOURCE_OWNER_ =:resourceOwner";
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "p");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new RowMapper<IPosition>() {
				
				public IPosition mapRow(ResultSet rs, int rowNum) throws SQLException {
					DefaultPosition p = new DefaultPosition();
					p.setId(rs.getString("ID_"));
					p.setCompanyId(rs.getString("COMPANY_ID_"));
					p.setName(rs.getString("NAME_"));
					p.setDesc(rs.getString("DESC_"));
					return p;
				}
			}, parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.P.name());
//			try {
//				this.pagingQuery(page1, queryString.toString(), countQueryString.toString(), parametersMap);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			Collection<IPosition> pList = new ArrayList<IPosition>();
//			IPositionService positionService = ContextHolder.getBean(IPositionService.BEAN_ID);
//			for (String positionId : page1.getEntities()) {
//				IPosition p = positionService.loadPositionById(positionId);
//				pList.add(p);
//			}
//			page.setEntities((Collection<T>) pList);
//			page.setEntityCount(page1.getEntityCount());
		} else if (ResourceAllocation.ResourceType.U.equals(resourceType)) {
			// URL
			String sql = "SELECT\n" +
					"	u.*\n" +
					"FROM\n" +
					"	bdf2_resource_allocation ra\n" +
					"INNER JOIN bdf2_url u ON u.ID_ = ra.RESOURCE_ID_\n" +
					"AND ra.RESOURCE_TYPE_ = 'U'\n" +
					"WHERE\n" +
					"	ra.RESOURCE_OWNER_ =:resourceOwner";
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "u");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new RowMapper<Url>() {
				
				public Url mapRow(ResultSet rs, int rowNum) throws SQLException {
					Url url =EntityRowMapperUtils.get(Url.class, rs, rowNum);
					return url;
				}
			}, parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.U.name());
//			List<String> urlIdList = this.query(queryString.toString(), parametersMap);
//			if (urlIdList.size() > 0) {
//				String queryUrl = "from " + Url.class.getName() + " where id in(:idList)";
//				String queryCountUrl = "select count(*) from " + Url.class.getName() + " where id in(:idList)";
//				try {
//					Map<String, Object> urlIdMap = new HashMap<String, Object>();
//					urlIdMap.put("idList", urlIdList);
//					this.pagingQuery(page, queryUrl, queryCountUrl, urlIdMap);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
		} else if (ResourceAllocation.ResourceType.G.equals(resourceType)) {
			// 群组
			String sql = "SELECT\n" +
					"	g.*\n" +
					"FROM\n" +
					"	bdf2_resource_allocation ra\n" +
					"INNER JOIN bdf2_group g ON g.ID_ = ra.RESOURCE_ID_\n" +
					"AND ra.RESOURCE_TYPE_ = 'G'\n" +
					"WHERE\n" +
					"	ra.RESOURCE_OWNER_ =:resourceOwner";
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "g");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new RowMapper<Group>() {
				
				public Group mapRow(ResultSet rs, int rowNum) throws SQLException {
					Group p = new Group();
					p.setId(rs.getString("ID_"));
					p.setCompanyId(rs.getString("COMPANY_ID_"));
					p.setName(rs.getString("NAME_"));
					p.setDesc(rs.getString("DESC_"));
					return p;
				}
			}, parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.G.name());
//			List<String> groupIdList = this.query(queryString.toString(), parametersMap);
//			if (groupIdList.size() > 0) {
//				String queryUrl = "from " + Group.class.getName() + " where id in(:idList)";
//				String queryCountUrl = "select count(*) from " + Group.class.getName() + " where id in(:idList)";
//				try {
//					Map<String, Object> groupIdParamsMap = new HashMap<String, Object>();
//					groupIdParamsMap.put("idList", groupIdList);
//					this.pagingQuery(page, queryUrl, queryCountUrl, groupIdParamsMap);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
		} else if (ResourceAllocation.ResourceType.D.equals(resourceType)) {
			// 部门
			String sql = "SELECT\n" +
					"	d.*\n" +
					"FROM\n" +
					"	bdf2_resource_allocation ra\n" +
					"INNER JOIN t_dept d ON d.ID_ = ra.RESOURCE_ID_\n" +
					"AND ra.RESOURCE_TYPE_ = 'D'\n" +
					"WHERE\n" +
					"	ra.RESOURCE_OWNER_ =:resourceOwner";
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "d");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new DefaultDeptRowMapper(), parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.D.name());
//			try {
//				this.pagingQuery(page1, queryString.toString(), countQueryString.toString(), parametersMap);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			List<IDept> deptList = new ArrayList<IDept>();
//			IDeptService deptService = ContextHolder.getBean(IDeptService.BEAN_ID);
//			for (String deptId : page1.getEntities()) {
//				IDept dept = deptService.loadDeptById(deptId);
//				deptList.add(dept);
//			}
//			page.setEntities((Collection<T>) deptList);
//			page.setEntityCount(page1.getEntityCount());
		} else if (ResourceAllocation.ResourceType.R.equals(resourceType)) {
			// 角色
			String sql = "SELECT\n" +
					"	r.*\n" +
					"FROM\n" +
					"	bdf2_resource_allocation ra\n" +
					"INNER JOIN bdf2_role r ON r.ID_ = ra.RESOURCE_ID_\n" +
					"AND ra.RESOURCE_TYPE_ = 'R'\n" +
					"WHERE\n" +
					"	ra.RESOURCE_OWNER_ =:resourceOwner";
			
			ParseResult result = this.jdbcDao.parseCriteria(criteria, true, "r");
			if(result!=null){
				sql += " and "+result.getAssemblySql();
				parametersMap.putAll(result.getValueMap());
			}
			this.jdbcDao.pagingQuery(page, sql, new RowMapper<Role>() {

				public Role mapRow(ResultSet rs, int rowNum) throws SQLException {
					Role role = new Role();
					role.setId(rs.getString("ID_"));
					role.setCompanyId(rs.getString("COMPANY_ID_"));
					role.setEnabled(rs.getBoolean("ENABLED_"));
//					if (rs.getObject("ENABLED_") != null) {
//						role.setEnabled(rs.getBoolean("ENABLED_"));
//					}
					role.setDesc(rs.getString("DESC_"));
					role.setName(rs.getString("NAME_"));
					return role;
				}

			}, parametersMap);
			
//			parametersMap.put("resourceType", ResourceAllocation.ResourceType.R.name());
//
//			try {
//				this.pagingQuery(page1, queryString.toString(), countQueryString.toString(), parametersMap);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			Collection<Role> pList = new ArrayList<Role>();
//
//			DefaultRoleService roleService = ContextHolder.getApplicationContext().getBean(DefaultRoleService.class);
//			Map<String, Object> params = new HashMap<String, Object>();
//			String sql = "SELECT R.ID_,R.COMPANY_ID_,R.ENABLED_,R.DESC_,R.NAME_ FROM BDF2_ROLE R where R.COMPANY_ID_=:COMPANY_ID and R.ID_=:ID";
//			params.put("COMPANY_ID", ContextHolder.getLoginUser().getCompanyId());
//			for (String roleId : page1.getEntities()) {
//				params.put("ID", roleId);
//				Role role = roleService.getNamedParameterJdbcTemplate().queryForObject(sql, params,
//						new RowMapper<Role>() {
//
//							public Role mapRow(ResultSet rs, int rowNum) throws SQLException {
//								Role role = new Role();
//								role.setId(rs.getString(1));
//								role.setCompanyId(rs.getString(2));
//								if (rs.getObject("ENABLED_") != null) {
//									role.setEnabled(rs.getBoolean(3));
//								}
//								role.setDesc(rs.getString(4));
//								role.setName(rs.getString(5));
//								return role;
//							}
//
//						});
//				pList.add(role);
//			}
//			page.setEntities((Collection<T>) pList);
//			page.setEntityCount(page1.getEntityCount());
		}
	}
}